package com.sky.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import com.sky.constant.MessageConstant;
import com.sky.context.BaseContext;
import com.sky.dto.*;
import com.sky.entity.*;
import com.sky.exception.AddressBookBusinessException;
import com.sky.exception.OrderBusinessException;
import com.sky.exception.ShoppingCartBusinessException;
import com.sky.mapper.*;
import com.sky.result.PageResult;
import com.sky.service.OrderService;
import com.sky.utils.HttpClientUtil;
import com.sky.vo.*;
import com.sky.websocket.WebSocketServer;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.security.auth.Subject;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

@Service
public class OrderServiceImpl implements OrderService {
    @Autowired
    private AddressBookMapper addressBookMapper;
    @Autowired
    private ShoppingCartMapper shoppingCartMapper;
    @Autowired
    private OrderMapper orderMapper;
    @Autowired
    private OrderDetailMapper orderDetailMapper;
    @Autowired
    private UserMapper userMapper;
    @Autowired
    private WebSocketServer webSocketServer;
    private Orders orders = new Orders();

    @Value("${sky.shop.address}")
    private String shop;
    @Value("${sky.baidu.ak}")
    private String key;
    @Override
    @Transactional(rollbackFor = Exception.class)
    public OrderSubmitVO submit(OrdersSubmitDTO ordersSubmitDTO) {
        //订单的提交逻辑
        //1.判断是否有地址 有地址id
        Long addressBookId = ordersSubmitDTO.getAddressBookId();
        AddressBook addressBook = addressBookMapper.getById(addressBookId);
        String address = addressBook.getProvinceName() + addressBook.getCityName() + addressBook.getDistrictName() + addressBook.getDetail();
        checkOutofRange(address);
        if(addressBook == null){
            throw new AddressBookBusinessException(MessageConstant.ADDRESS_BOOK_IS_NULL);
        }
        //2.判断购物车数据是否为空 有用户id可以直接查
        ShoppingCart shoppingCart = new ShoppingCart();
        shoppingCart.setUserId(BaseContext.getCurrentId());
        List<ShoppingCart> shoppingCartList = shoppingCartMapper.list(shoppingCart);
        if(shoppingCartList == null){
            throw new ShoppingCartBusinessException(MessageConstant.SHOPPING_CART_IS_NULL);
        }
        User byId = userMapper.getById(BaseContext.getCurrentId());//获取用户

        //3.插入一条订单数据
        BeanUtils.copyProperties(ordersSubmitDTO,orders);
        orders.setAddress(addressBook.getDetail());
        orders.setUserId(BaseContext.getCurrentId());
        orders.setNumber(String.valueOf(System.currentTimeMillis()));//当前系统的毫秒值作为订单号
        orders.setStatus(Orders.PENDING_PAYMENT);
        orders.setUserId(BaseContext.getCurrentId());
        orders.setUserName(byId.getName());
        orders.setOrderTime(LocalDateTime.now());
        orders.setPayStatus(Orders.UN_PAID);
        orders.setConsignee(addressBook.getConsignee());
        orders.setPhone(addressBook.getPhone());

        orderMapper.insert(orders);

        //4.接着要插入信息到订单详情
        List<OrderDetail> orderDetailList = new ArrayList<>();
        for (ShoppingCart cart : shoppingCartList) {
            OrderDetail orderDetail = new OrderDetail();
            BeanUtils.copyProperties(cart,orderDetail);
            orderDetail.setOrderId(orders.getId());
            orderDetailList.add(orderDetail);
        }
        //批量插入订单详情信息
        orderDetailMapper.insertBatch(orderDetailList);

        //5.清空购物车数据
        shoppingCartMapper.deleteAll(orders.getUserId());

        return OrderSubmitVO.builder().
                id(orders.getId()).orderNumber(orders.getNumber()).
                orderAmount(orders.getAmount()).
                orderTime(orders.getOrderTime()).build();
    }
    /**
     * 订单支付
     *
     * @param ordersPaymentDTO
     * @return
     */
    public OrderPaymentVO payment(OrdersPaymentDTO ordersPaymentDTO) throws Exception {
        // 当前登录用户id
        Long userId = BaseContext.getCurrentId();
        User user = userMapper.getById(userId);
/*        //调用微信支付接口，生成预支付交易单
        JSONObject jsonObject = weChatPayUtil.pay(
                ordersPaymentDTO.getOrderNumber(), //商户订单号
                new BigDecimal(0.01), //支付金额，单位 元
                "苍穹外卖订单", //商品描述
                user.getOpenid() //微信用户的openid
        );

        if (jsonObject.getString("code") != null && jsonObject.getString("code").equals("ORDERPAID")) {
            throw new OrderBusinessException("该订单已支付");
        }
*/
        JSONObject jsonObject = new JSONObject();
        jsonObject.put("code","ORDERPAID");
        OrderPaymentVO vo = jsonObject.toJavaObject(OrderPaymentVO.class);
        vo.setPackageStr(jsonObject.getString("package"));
        Integer OrderPaidStatus = Orders.PAID;//支付状态，已支付
        Integer OrderStatus = Orders.TO_BE_CONFIRMED;  //订单状态，待接单
        LocalDateTime check_out_time = LocalDateTime.now();//更新支付时间
        //这里没法做商户支付 直接模拟支付成功后改变订单状态 这里直接进行催单了
        Map map = new HashMap();
        map.put("type",1);//1 来单提醒  2表示客户催单
        map.put("orderId",this.orders.getId());
        map.put("content","订单号：" + orders.getNumber());
        //转换为JSON字符串
        String s = JSON.toJSONString(map);
        webSocketServer.sendToAllClient(s);
        orderMapper.updateStatus(OrderStatus, OrderPaidStatus, check_out_time, this.orders.getId());
        return vo;
    }

    /**
     * 订单信息
     * @param id
     * @return
     */
    @Override
    public OrderVO getOrderwithDetail(Long id) {
        //获取订单的信息
        Orders orders = orderMapper.getById(id);
        //获取订单详情
        List<OrderDetail> byOrderId = orderDetailMapper.getByOrderId(id);
        OrderVO orderVO = new OrderVO();
        BeanUtils.copyProperties(orders,orderVO);
        orderVO.setOrderDetailList(byOrderId);
        return orderVO;
    }

    @Override
    public PageResult page(OrdersPageQueryDTO ordersPageQueryDTO) {

        ordersPageQueryDTO.setUserId(BaseContext.getCurrentId());
        PageHelper.startPage(ordersPageQueryDTO.getPage(),ordersPageQueryDTO.getPageSize());
        //先对订单进行分页查询 然后把订单详情查询出来
        Page<Orders> page = orderMapper.page(ordersPageQueryDTO);
        List<OrderVO> orderVOList = new ArrayList<>();
        if(page != null && page.size() > 0){
            for (Orders o : page) {
                OrderVO orderVO = new OrderVO();
                BeanUtils.copyProperties(o,orderVO);
                //将订单详情查询出来
                List<OrderDetail> byOrderId = orderDetailMapper.getByOrderId(o.getId());
                orderVO.setOrderDetailList(byOrderId);
                orderVOList.add(orderVO);
            }
        }
        return new PageResult(page.getTotal(),orderVOList);
    }

    @Override
    public void cancel(Long id) {
        Orders o = orderMapper.getById(id);
        //除了订单状态是1待付款和2待接单其他不允许取消
        if(o.getStatus() >  2){
            o.setRejectionReason("不允许取消");
            throw new OrderBusinessException("不允许取消");
        }
        //假设是已付款就支付状态直接修改为已退款
        if(o.getPayStatus() == Orders.PAID){
            o.setPayStatus(Orders.REFUND);
        }
        o.setStatus(Orders.CANCELLED);
        o.setCancelReason("用户取消");
        o.setCancelTime(LocalDateTime.now());
        orderMapper.update(o);
    }

    /**
     * 再来一单
     * @param id
     */
    @Override
    public void repetition(Long id) {
        //再来一单重新加入购物车
        Long UserId = BaseContext.getCurrentId();
        List<OrderDetail> orderDetailList = orderDetailMapper.getByOrderId(id);
        //将订单详情转换为购物车列表
        List<ShoppingCart> shopcarts = orderDetailList.stream().map(orderDetail -> {
            ShoppingCart shoppingCart = new ShoppingCart();
            shoppingCart.setUserId(UserId);
            BeanUtils.copyProperties(orderDetail, shoppingCart);
            shoppingCart.setCreateTime(LocalDateTime.now());
            return shoppingCart;
        }).collect(Collectors.toList());

        //进行批量的购物车数据插入
        shoppingCartMapper.insertBatch(shopcarts);
    }

    @Override
    public PageResult conditionSearch(OrdersPageQueryDTO ordersPageQueryDTO) {

        PageHelper.startPage(ordersPageQueryDTO.getPage(),ordersPageQueryDTO.getPageSize());
        //先对订单进行分页查询 然后把订单详情查询出来
        Page<Orders> page = orderMapper.page(ordersPageQueryDTO);
        List<OrderVO> orderVOList = new ArrayList<>();
        if(page != null && page.size() > 0){
            for (Orders o : page) {
                OrderVO orderVO = new OrderVO();
                BeanUtils.copyProperties(o,orderVO);
                //将订单详情查询出来
                List<OrderDetail> byOrderId = orderDetailMapper.getByOrderId(o.getId());
                orderVO.setOrderDetailList(byOrderId);
                orderVO.setOrderDishes(byOrderId.stream().map(orderDetail -> orderDetail.getName() + "*" + orderDetail.getNumber()).collect(Collectors.joining(",")));
                orderVOList.add(orderVO);
            }
        }
        return new PageResult(page.getTotal(),orderVOList);
    }

    @Override
    public OrderStatisticsVO statistics() {
        OrderStatisticsVO orderStatisticsVO = new OrderStatisticsVO();
        //subject类型 map的值要赋值给subject
        Integer toBeConfirmedNum = orderMapper.getCountByStatus(Orders.TO_BE_CONFIRMED);//待接单
        Integer confirmedNum = orderMapper.getCountByStatus(Orders.CONFIRMED);//待派送
        Integer deNum = orderMapper.getCountByStatus(Orders.DELIVERY_IN_PROGRESS);//派送中
        orderStatisticsVO.setConfirmed(confirmedNum);
        orderStatisticsVO.setDeliveryInProgress(deNum);
        orderStatisticsVO.setToBeConfirmed(toBeConfirmedNum);
        return orderStatisticsVO;

    }

    @Override
    public void confirm(OrdersConfirmDTO ordersConfirmDTO) {
        //Orders o = orderMapper.getById(Long.valueOf(id));
        Orders o = Orders.builder().id(ordersConfirmDTO.getId()).status(Orders.CONFIRMED).build();
        orderMapper.update(o);
    }

    /**
     * 进行一个派单
     * @param id
     */
    @Override
    public void delivery(Long id) {
        Orders o = orderMapper.getById(id);
        if(o != null && o.getStatus() == Orders.CONFIRMED){
            //只有接单的才能进行派送
            o = Orders.builder().id(id).status(Orders.DELIVERY_IN_PROGRESS).build();
            orderMapper.update(o);
        }else{
            throw new OrderBusinessException(MessageConstant.ORDER_STATUS_ERROR);
        }

    }

    /**
     * 商家拒单
     * @param ordersRejectionDTO
     */
    @Override
    public void reject(OrdersRejectionDTO ordersRejectionDTO) {
        //只有在待接单的状态才能进行拒单
        Orders o = orderMapper.getById(ordersRejectionDTO.getId());
        if(o == null || o.getStatus() != Orders.TO_BE_CONFIRMED){
            throw new OrderBusinessException(MessageConstant.ORDER_STATUS_ERROR);
        }
        //由于没有退款功能 直接进行退款
        o = Orders.builder().id(ordersRejectionDTO.getId()).
                rejectionReason(ordersRejectionDTO.getRejectionReason())
                .status(Orders.CANCELLED).cancelTime(LocalDateTime.now()).
                payStatus(Orders.REFUND).build();
        orderMapper.update(o);
    }

    /**
     * 管理员取消订单
     * @param ordersCancelDTO
     */
    @Override
    public void admincancel(OrdersCancelDTO ordersCancelDTO) {
        //获取订单
        Orders o = orderMapper.getById(ordersCancelDTO.getId());
        if(o == null || o.getStatus() >= Orders.DELIVERY_IN_PROGRESS) {//派送中 已完成 已退款之类的就不让取消了
            throw new OrderBusinessException("订单不能取消了");
        }
        o = Orders.builder().id(ordersCancelDTO.getId()).status(Orders.CANCELLED)
                .cancelReason(ordersCancelDTO.getCancelReason())
                .cancelTime(LocalDateTime.now()).payStatus(Orders.REFUND).build();
        orderMapper.update(o);
    }

    /**
     * 完成订单
     * @param id
     */
    @Override
    public void complete(Long id) {
        //只有派送中的订单才能完成
        Orders o = orderMapper.getById(id);
        if(o == null || o.getStatus() != Orders.DELIVERY_IN_PROGRESS){
            throw new OrderBusinessException(MessageConstant.ORDER_STATUS_ERROR);
        }
        o = Orders.builder().id(id).status(Orders.COMPLETED)
                .deliveryTime(LocalDateTime.now()).build();
        orderMapper.update(o);
    }

    /**
     * 催单
     * @param id
     */
    @Override
    public void reminder(Long id) {
        Orders o = orderMapper.getById(id);
        if(o== null){
            throw new OrderBusinessException(MessageConstant.ORDER_NOT_FOUND);
        }
        Map map = new HashMap();
        map.put("orderId",id);
        map.put("type",2);//表示客户催单
        map.put("content",o.getNumber() + ":请尽快处理订单");
        String jsonString = JSON.toJSONString(map);
        webSocketServer.sendToAllClient(jsonString);
    }

    /**
     * 判断地址是否超出范围
     * @param address
     */
    private void checkOutofRange(String address){
        String url = "https://api.map.baidu.com/geocoding/v3?";
        Map<String,String> map = new HashMap<>();
        map.put("address",address);
        map.put("output","json");
        map.put("ak",key);
        String user = HttpClientUtil.doGet(url, map);
        //System.out.println(s);
        //解析用户的地址 得到经纬度坐标
        JSONObject jsonObject = JSONObject.parseObject(user);
        JSONObject location = jsonObject.getJSONObject("result").getJSONObject("location");
        String UserLng  = location.getString("lng");
        String UserLat = location.getString("lat");
        BigDecimal lng = new BigDecimal(UserLng).setScale(6, RoundingMode.HALF_UP);
        BigDecimal lat = new BigDecimal(UserLat).setScale(6, RoundingMode.HALF_UP);

        String formattedLng = lng.toString();
        String formattedLat = lat.toString();

        String UserLngLat = formattedLat + "," + formattedLng;
        //System.out.println(UserLngLat);

        map.put("address",shop);
        map.put("output","json");
        map.put("ak",key);
        String shopget = HttpClientUtil.doGet(url, map);
        //System.out.println(s);
        //解析用户的地址 得到经纬度坐标
        jsonObject = JSONObject.parseObject(shopget);
        location = jsonObject.getJSONObject("result").getJSONObject("location");
        //小数点不超过6位
        String shopLng = location.getString("lng");
        String shopLat = location.getString("lat");

        lng = new BigDecimal(shopLng).setScale(6, RoundingMode.HALF_UP);
        lat = new BigDecimal(shopLat).setScale(6, RoundingMode.HALF_UP);

        formattedLng = lng.toString();
        formattedLat = lat.toString();

        String shopLngLat = formattedLat + "," + formattedLng;
        //System.out.println(shopLngLat);

        url = "https://api.map.baidu.com/directionlite/v1/driving?";
        map.clear();
        map.put("origin",shopLngLat);
        map.put("destination",UserLngLat);
        map.put("ak",key);
        String driving = HttpClientUtil.doGet(url, map);
        jsonObject = JSONObject.parseObject(driving);
        if(jsonObject.getInteger("status") != 0){
            throw new RuntimeException();
        }
        Double aDouble = jsonObject
                .getJSONObject("result")
                .getJSONArray("routes")
                .getJSONObject(0)
                .getDouble("distance");
        if(aDouble > 5000){
            throw new OrderBusinessException("超出配送范围");
        }
    }
}
